home *** CD-ROM | disk | FTP | other *** search
- // File: SimpleApp.c
- //
- // This is a trivial PowerPC application which loads and runs external code modules
- // from PEF containers in either resources or the Data fork of a file.
- //
- // A more complete example can be found in "ModApp", which is located in the Macintosh
- // on RISC Software Developer's Kit, in the Metrowerks "Code Warrior" product, or in
- // the classroom courses at Apple's "Developer University."
- //
-
- #ifndef powerc
- #error This code only runs on a PowerPC machine.
- #endif
-
- #include <Types.h>
- #include <Memory.h>
- #include <Resources.h>
- #include <Quickdraw.h>
- #include <Menus.h>
- #include <Events.h>
- #include <Windows.h>
- #include <Dialogs.h>
- #include <AppleEvents.h>
- #include <StandardFile.h>
- #include <Files.h>
-
- #include <FragLoad.h>
-
-
- // === The interface to our example code
- typedef Boolean (*MainRoutinePtr) (EventRecord *theEvent, WindowPtr currWindow,
- QDGlobals *qdAddress);
-
- // === Useful constants
- enum {
- kAppleMenu = 128,
- kFileMenu = 129,
- kOpenCommand = 1,
- kQuitCommand = 3
- };
-
- enum {
- rAboutAlert = 128,
- rErrorAlert = 129,
- rMainWindow = 128
- };
-
- enum {
- kPEFData = 'DPEF',
- kPEFResource = 'RPEF'
- };
-
- // === Global variables
- QDGlobals qd;
- Boolean gDone = false;
- MainRoutinePtr gMain = NULL; // If we have some code loaded, this is the entry point
- ConnectionID gConnID = 0; // A "reference number" for our loaded PowerPC code
- Handle gCodeResource = NULL; // If we loaded the code as a resource, this is a
- // handle to the resource
- WindowPtr gOurWindow = NULL;
-
- // === Function prototypes
- void Initialize (void);
- void MainLoop (void);
- void DoMouseDown (EventRecord theEvent);
- void DoMenu (long menuCode);
- void FindAndOpenCode (void);
- void LoadCode (FSSpec fileSpec, OSType fileType);
- void UnloadCode(void);
- void LoadFailed(OSErr err, Str255 errName);
- pascal OSErr HandleOAPP (AEDescList *aevt, AEDescList *reply, long refCon);
- pascal OSErr HandleODOC (AEDescList *aevt, AEDescList *reply, long refCon);
- pascal OSErr HandleQUIT (AEDescList *aevt, AEDescList *reply, long refCon);
-
- // === Start of our code
- main()
- {
- Initialize();
- MainLoop();
- }
-
-
- // Initialize the ROM managers, set up our menu bar and (only) window, and
- // install our Apple event handlers.
- void Initialize()
- {
- MenuHandle appleMenu;
- MenuHandle fileMenu;
-
- // Standard "boilerplate" initialization
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(NULL);
- FlushEvents(everyEvent, 0);
-
- // Set up the menu bar
- appleMenu = GetMenu(kAppleMenu);
- if (appleMenu == NULL) {
- // Our resource file is missing! Bail out!
- ExitToShell();
- }
- AddResMenu(appleMenu, 'DRVR'); // Add Desk Accessories
- InsertMenu(appleMenu, 0);
- fileMenu = GetMenu(kFileMenu);
- InsertMenu(fileMenu, 0);
- DrawMenuBar();
-
- // Construct a window
- gOurWindow = GetNewCWindow(rMainWindow, NULL, (WindowPtr)-1L);
- SetPort(gOurWindow);
-
- // Install our Apple event handlers
- AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, NewAEEventHandlerProc(HandleOAPP), 0, false);
- AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerProc(HandleODOC), 0, false);
- AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerProc(HandleQUIT), 0, false);
-
- InitCursor();
- }
-
-
- // Collect events until the user selects "Quit" (or we get a "Quit" Apple
- // event.) If we've loaded some PowerPC code, then give that code a chance
- // to execute the event first.
- void MainLoop()
- {
- EventRecord theEvent;
-
- while (!gDone) {
- WaitNextEvent(everyEvent, &theEvent, 15L, NULL);
- // Do we have some code loaded? If so, pass the event to that code
- if (gMain != NULL) {
- Boolean eventHandled;
-
- eventHandled = gMain(&theEvent, FrontWindow(), &qd);
- if (eventHandled)
- continue; // The external code handled the event, so get another
- }
-
- // The external code didn't handle the event, so we will
- switch (theEvent.what) {
- case mouseDown:
- DoMouseDown(theEvent);
- break;
-
- case keyDown: {
- // See if the comamnd key is down. If it is, handle this as
- // a menu command
- char theKey = (theEvent.message & charCodeMask);
-
- if (theEvent.modifiers & cmdKey)
- DoMenu(MenuKey(theKey));
- }
- break;
-
- case updateEvt: {
- WindowPtr theWindow = (WindowPtr)theEvent.message;
-
- BeginUpdate(theWindow);
- // EraseRect(&theWindow->portRect);
- EndUpdate(theWindow);
- }
- break;
-
- case kHighLevelEvent:
- AEProcessAppleEvent(&theEvent);
- }
- }
- }
-
- // Handle mouse clicks either in the menubar or in a window
- void DoMouseDown (EventRecord theEvent)
- {
- short part;
- WindowPtr theWindow;
-
- part = FindWindow(theEvent.where, &theWindow);
- switch (part) {
- case inMenuBar:
- DoMenu(MenuSelect(theEvent.where));
- break;
-
- case inSysWindow:
- SystemClick(&theEvent, theWindow);
- break;
-
- case inDrag: {
- Rect dragRect = qd.screenBits.bounds;
- dragRect.top = GetMBarHeight();
- DragWindow(theWindow, theEvent.where, &dragRect);
- }
- break;
- }
- }
-
-
- // Code to handle the File and Apple menus
- void DoMenu (long menuCode)
- {
- short menuID = menuCode >> 16;
- short itemID = menuCode & 0x0000FFFF;
-
- switch (menuID) {
- case kAppleMenu:
- if (itemID == 1)
- Alert(128, NULL); // Display the "About" box
- break;
-
- case kFileMenu:
- if (itemID == kOpenCommand) {
- FindAndOpenCode();
- }
- else if (itemID == kQuitCommand)
- gDone = true;
- break;
- }
- }
-
-
- // Ask the user to locate a bit of code for us, then load
- // and execute the code
- void FindAndOpenCode ()
- {
- // Open a file of type 'PEF ' or a resource file
- SFTypeList typeList = {kPEFData, kPEFResource};
- StandardFileReply reply;
-
- StandardGetFile(NULL, 3, typeList, &reply);
- if (reply.sfGood)
- LoadCode(reply.sfFile, reply.sfType);
- }
-
-
- // Load a bit of PowerPC code which is external to this application
- void LoadCode (FSSpec fileSpec, OSType fileType)
- {
- OSErr err = noErr;
- Str255 errName;
-
- // We have a file, so open it and load the code
- // But first, we have to unload any previous code...
- UnloadCode();
-
- if (fileType == kPEFResource) {
- // It's a resource file, so load the code from a resource
- short refNum;
-
- refNum = FSpOpenResFile(&fileSpec, fsCurPerm);
- if (ResError() == noErr) {
- gCodeResource = Get1IndResource(kPEFResource, 1);
- if (gCodeResource != NULL) {
- DetachResource(gCodeResource);
- HLock(gCodeResource);
- // We have the code, but it's not ready to use yet
- // We have to ask the Code Fragment Manager to "prepare"
- // the code for execution and return the "main" address
- // to us
- err = GetMemFragment (*gCodeResource, 0, fileSpec.name,
- kLoadNewCopy, &gConnID, (Ptr*)&gMain,
- errName);
- if (err) {
- // Something went wrong, so tell the user
- LoadFailed(err, errName);
- UnloadCode();
- }
- }
- CloseResFile(refNum);
- }
-
- } else {
- // It's not a resource file, so load the code from the data fork
-
- err = GetDiskFragment (&fileSpec, 0, 0, fileSpec.name,
- kLoadNewCopy, &gConnID, (Ptr*)&gMain,
- errName);
- if (err) {
- // Something went wrong, so tell the user
- LoadFailed(err, errName);
- UnloadCode();
- }
- }
- if (err == noErr) {
- // Invalidate the window so the external code gets a chance to
- // draw in it
- SetPort(gOurWindow);
- InvalRect(&gOurWindow->portRect);
- }
- }
-
-
- // If some code is already loaded, this routine tells the CFM to unload the code
- // and then disposes of the memory (if the code was loaded in from a resource)_
- void UnloadCode()
- {
- if (gMain != NULL) {
- // Unload the old module
- CloseConnection(&gConnID);
- gMain = NULL;
- }
-
- // If the old code was in a resource, release the memory
- // (we've already detached the resource, so we can free it
- // with a simple DisposeHandle)
- if (gCodeResource != NULL) {
- DisposeHandle(gCodeResource);
- gCodeResource = NULL;
- }
- }
-
-
- // Report an error in loading some code
- void LoadFailed(OSErr err, Str255 errName)
- {
- Str31 errNumString;
-
- NumToString(err, errNumString);
- ParamText(errNumString, errName, NULL, NULL);
- Alert(rErrorAlert, NULL);
- }
-
-
- // Apple event handlers for "Open Application", "Open Document", and
- // "Quit"
- pascal OSErr HandleOAPP (AEDescList *aevt, AEDescList *reply, long refCon)
- {
- FindAndOpenCode();
- return noErr;
- }
-
-
- pascal OSErr HandleODOC (AEDescList *aevt, AEDescList *reply, long refCon)
- // We'll get this if somebody double-clicks on one of our code files
- {
- AEDesc fileListDesc = {'NULL', NULL};
- FSSpec theFile;
- OSErr err;
-
- // Extract an alias to the file into "fileListDesc"
- // (if the user selected multiple files, we'll only look at the
- // first one, but asking for a list just simplifies the code.)
- err = AEGetKeyDesc( aevt, keyDirectObject, typeAEList, &fileListDesc );
- if (err == noErr) {
- // Get the first file in the list
- // Even though the event contains a list of alises, the Apple Event Manager
- // will convert each alias to an FSSpec if we ask it to.
- DescType actualType;
- long actualSize;
- AEKeyword actualKeyword;
-
- err = AEGetNthPtr( &fileListDesc, 1, typeFSS, &actualKeyword,
- &actualType, (Ptr)&theFile, sizeof(theFile), &actualSize);
- if (err == noErr) {
- // LoadCode wants the file's type, so we have to get that
- FInfo finderInfo;
-
- FSpGetFInfo(&theFile, &finderInfo);
- LoadCode(theFile, finderInfo.fdType);
- }
- }
- AEDisposeDesc(&fileListDesc);
- return err;
- }
-
-
- pascal OSErr HandleQUIT (AEDescList *aevt, AEDescList *reply, long refCon)
- {
- gDone = true;
- return noErr;
- }
-